const axios = require("axios");

const fs = require("fs");

const path = require("path");

const {pipeline} = require("stream");

const {promisify} = require("util");

const pipelineAsync = promisify(pipeline);

/**

 *

 * @param url 远程文件地址

 * @param filePath 下载到本地的文件路径

 * @param httpHeader 远程文件的附加header，一般有basic认证

 * @param chunkSize 分片文件的大小限制

 */

async function downloadFile (url, filePath, httpHeader, chunkSize) {

    const response = await axios({

        method: "head",

        url: url,

        responseType: "stream",

        headers: httpHeader

    });

    // 根据content-length计算分片的数量

    const totalLength = parseInt(response.headers["content-length"], 10);

    // console.debug(`totalLength=${totalLength}`);

    const numChunks = Math.ceil(totalLength / chunkSize);

    // loop 一个一个发request 范围性的下载文件

    for (let i = 0; i < numChunks; i++) {

        const start = i * chunkSize;

        const end = Math.min(start + chunkSize - 1, totalLength - 1);

        // console.debug(`bytes=${start}-${end}`);

        const fileName = url.split("/");

        const chunkPath = path.join(filePath, `${fileName[fileName.length - 1]}.part_${i}`);

        const stream = fs.createWriteStream(chunkPath);

        stream.on("finish", () => {

            stream.close();

            console.log(`part_${i} download finish`);

        });

        stream.on("error", (error) => {

            console.log(`part_${i} download error:${error}`);

        });

        let subResponse = await axios({

            method: "get",

            url: url,

            responseType: "stream",

            headers: Object.assign({Range: `bytes=${start}-${end}`}, httpHeader)

        });

        await pipelineAsync(subResponse.data, stream);

        console.log(`part_${i} finished`);

    }

}

 

// 使用示例

const fileUrl = "http://localhost:8080/download";

const savePath = "/Users/a123456/Downloads/temp/";

downloadFile(

    fileUrl,

    savePath,

    {

        Authorization:

            ""

    },

    200 * 1024 * 1024

)

    .then(() => console.log("File downloaded successfully"))

    .catch((err) => console.error("Download failed", err));